module raob_mongo_mod

  use iso_c_binding
  use mongof_common_mod
  use datetime
  use string
  use container
  use flogger
  use params_mod
  use data_translators_utils_mod
  use raob_mod

  implicit none

  private

  public raob_mongo_write

  interface
    integer function raob_mongoc_insert_platform(cid, name, lon, lat, z) result(res) bind(c, name='raob_mongoc_insert_platform')
      use iso_c_binding
      integer(c_int), intent(in) :: cid
      character(c_char), intent(in) :: name
      real(c_float), intent(in) :: lon
      real(c_float), intent(in) :: lat
      real(c_float), intent(in) :: z
    end function raob_mongoc_insert_platform

    integer function raob_mongoc_insert_record(cid, name, timestamp, &
                                                           sfc_ta,  sfc_p,  sfc_sh,  sfc_ua,  sfc_va, &
                                                man_nlev,  man_ta,  man_p,  man_sh,  man_ua,  man_va, &
                                               sigt_nlev, sigt_ta, sigt_p, sigt_sh, sigt_ua, sigt_va, &
                                               sigw_nlev,          sigw_p,          sigw_ua, sigw_va, &
                                               trop_nlev, trop_ta, trop_p, trop_sh, trop_ua, trop_va) &
                                               result(res) bind(c, name='raob_mongoc_insert_record')
      use iso_c_binding
      integer(c_int), intent(in) :: cid
      character(c_char), intent(in) :: name
      real(c_double), intent(in) :: timestamp
      real(c_float), intent(in) :: sfc_ta
      real(c_float), intent(in) :: sfc_p
      real(c_float), intent(in) :: sfc_sh
      real(c_float), intent(in) :: sfc_ua
      real(c_float), intent(in) :: sfc_va
      integer(c_int), intent(in) :: man_nlev
      real(c_float), intent(in), dimension(:) :: man_ta
      real(c_float), intent(in), dimension(:) :: man_p
      real(c_float), intent(in), dimension(:) :: man_sh
      real(c_float), intent(in), dimension(:) :: man_ua
      real(c_float), intent(in), dimension(:) :: man_va
      integer(c_int), intent(in) :: sigt_nlev
      real(c_float), intent(in), dimension(:) :: sigt_ta
      real(c_float), intent(in), dimension(:) :: sigt_p
      real(c_float), intent(in), dimension(:) :: sigt_sh
      real(c_float), intent(in), dimension(:) :: sigt_ua
      real(c_float), intent(in), dimension(:) :: sigt_va
      integer(c_int), intent(in) :: sigw_nlev
      real(c_float), intent(in), dimension(:) :: sigw_p
      real(c_float), intent(in), dimension(:) :: sigw_ua
      real(c_float), intent(in), dimension(:) :: sigw_va
      integer(c_int), intent(in) :: trop_nlev
      real(c_float), intent(in), dimension(:) :: trop_ta
      real(c_float), intent(in), dimension(:) :: trop_p
      real(c_float), intent(in), dimension(:) :: trop_sh
      real(c_float), intent(in), dimension(:) :: trop_ua
      real(c_float), intent(in), dimension(:) :: trop_va
    end function raob_mongoc_insert_record
  end interface

contains

  subroutine raob_mongo_write(mongo_uri, mongo_db, mongo_col, stations, records)

    character(*), intent(in) :: mongo_uri
    character(*), intent(in) :: mongo_db
    character(*), intent(in) :: mongo_col
    type(hash_table_type), intent(in) :: stations
    type(linked_list_type), intent(in) :: records

    integer(c_int) cid_station, cid_record
    character(10) sid
    type(linked_list_iterator_type) it

    call mongoc_init()

    call handle_mongo_error(mongoc_connect('mongodb://' // trim(mongo_uri), trim(mongo_db), &
      trim(mongo_col) // '_stations' // char(0), cid_station), __FILE__, __LINE__)

    call handle_mongo_error(mongoc_connect('mongodb://' // trim(mongo_uri), trim(mongo_db), &
      trim(mongo_col) // '_records' // char(0), cid_record), __FILE__, __LINE__)

    call handle_mongo_error(mongoc_create_platform_index(cid_station), __FILE__, __LINE__)
    call handle_mongo_error(mongoc_create_record_index(cid_record), __FILE__, __LINE__)

    it = linked_list_iterator(records)
    do while (.not. it%ended())
      select type (record => it%value)
      type is (raob_record_type)
        sid = trim(record%station%name) // char(0)
        call handle_mongo_error(raob_mongoc_insert_platform(cid_station, sid, &
          record%station%lon, record%station%lat, record%station%z), __FILE__, __LINE__)
        call handle_mongo_error(raob_mongoc_insert_record(cid_record, sid, record%time%timestamp(), &
                                   record%tas, record%ps, record%shs, record%uas, record%vas, &
              record%man %num_level, record%man %ta, record%man %p, record%man %sh, record%man %ua, record%man %va, &
              record%sigt%num_level, record%sigt%ta, record%sigt%p, record%sigt%sh, record%sigt%ua, record%sigt%va, &
              record%sigw%num_level,                 record%sigw%p,                 record%sigw%ua, record%sigw%va, &
              record%trop%num_level, record%trop%ta, record%trop%p, record%trop%sh, record%trop%ua, record%trop%va  &
          ), __FILE__, __LINE__)
      end select
      call it%next()
    end do

    call mongoc_final()

  end subroutine raob_mongo_write

end module raob_mongo_mod
